home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 58 / pcpp58a.iso / extras / quake 3 source / Q3A_ToolSource.exe / Main / models.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-02  |  55.3 KB  |  2,185 lines

  1. #include <assert.h>
  2. #include "q3data.h"
  3.  
  4. //=================================================================
  5.  
  6. static void OrderSurfaces( void );
  7. static void LoadBase( const char *filename );
  8. static int    LoadModelFile( const char *filename, polyset_t **ppsets, int *pnumpolysets );
  9.  
  10. #define MAX_SURFACE_TRIS    (SHADER_MAX_INDEXES / 3)
  11. #define MAX_SURFACE_VERTS    SHADER_MAX_VERTEXES
  12.  
  13. #define MD3_TYPE_UNKNOWN 0
  14. #define MD3_TYPE_BASE3DS 1
  15. #define MD3_TYPE_SPRITE  2
  16. #define MD3_TYPE_ASE     3
  17.  
  18. #define MAX_ANIM_FRAMES        512
  19. #define MAX_ANIM_SURFACES    32
  20.  
  21. typedef struct
  22. {
  23.     polyset_t *frames;
  24.     int numFrames;
  25. } SurfaceAnimation_t;
  26.  
  27. typedef struct
  28. {
  29.     polyset_t *surfaces[MAX_ANIM_SURFACES];
  30.     int numSurfaces;
  31. } ObjectAnimationFrame_t;
  32.  
  33. typedef struct {
  34.     vec3_t        xyz;
  35.     vec3_t        normal;
  36.     vec3_t        color;
  37.     float        st[2];
  38.     int            index;
  39. } baseVertex_t;
  40.     
  41. typedef struct {
  42.     baseVertex_t    v[3];
  43. } baseTriangle_t;
  44.  
  45. //================================================================
  46.  
  47. typedef struct
  48. {
  49.     md3Surface_t    header;
  50.     md3Shader_t        shaders[MD3_MAX_SHADERS];
  51.     // all verts (xyz_normal)
  52.     float    *verts[MD3_MAX_FRAMES];
  53.  
  54.     baseTriangle_t    baseTriangles[MD3_MAX_TRIANGLES];
  55.  
  56.     // the triangles will be sorted so that they form long generalized tristrips
  57.     int                orderedTriangles[MD3_MAX_TRIANGLES][3];
  58.     int                lodTriangles[MD3_MAX_TRIANGLES][3];
  59.     baseVertex_t    baseVertexes[MD3_MAX_VERTS];
  60.  
  61. } md3SurfaceData_t;
  62.  
  63. typedef struct
  64. {
  65.     int            skinwidth, skinheight;
  66.     
  67.     md3SurfaceData_t surfData[MD3_MAX_SURFACES];
  68.  
  69.     md3Tag_t        tags[MD3_MAX_FRAMES][MD3_MAX_TAGS];
  70.     md3Frame_t        frames[MD3_MAX_FRAMES];
  71.  
  72.     md3Header_t    model;
  73.     float        scale_up;            // set by $scale
  74.     vec3_t        adjust;                // set by $origin
  75.     vec3_t        aseAdjust;
  76.     int            fixedwidth, fixedheight;    // set by $skinsize
  77.  
  78.     int            maxSurfaceTris;
  79.  
  80.     int            lowerSkipFrameStart, lowerSkipFrameEnd;
  81.     int            maxUpperFrames;
  82.     int            maxHeadFrames;
  83.     int            currentLod;
  84.     float        lodBias;
  85.  
  86.     int            type;        // MD3_TYPE_BASE, MD3_TYPE_OLDBASE, MD3_TYPE_ASE, or MD3_TYPE_SPRITE
  87.  
  88. } q3data;
  89.  
  90. q3data g_data;
  91.  
  92. // the command list holds counts, the count * 3 xyz, st, normal indexes
  93. // that are valid for every frame
  94. char        g_cddir[1024];
  95. char        g_modelname[1024];
  96.  
  97. //==============================================================
  98.  
  99. /*
  100. ===============
  101. ClearModel
  102. ===============
  103. */
  104. void ClearModel (void)
  105. {
  106.     int i;
  107.  
  108.     g_data.type = MD3_TYPE_UNKNOWN;
  109.  
  110.     for ( i = 0; i < MD3_MAX_SURFACES; i++ )
  111.     {
  112.         memset( &g_data.surfData[i].header, 0, sizeof( g_data.surfData[i].header ) );
  113.         memset( &g_data.surfData[i].shaders, 0, sizeof( g_data.surfData[i].shaders ) );
  114.         memset( &g_data.surfData[i].verts, 0, sizeof( g_data.surfData[i].verts ) );
  115.     }
  116.  
  117.     memset( g_data.tags, 0, sizeof( g_data.tags ) );
  118.  
  119.     for ( i = 0; i < g_data.model.numSurfaces; i++ )
  120.     {
  121.         int j;
  122.  
  123.         for ( j = 0; j < g_data.surfData[i].header.numShaders; j++ )
  124.         {
  125.             memset( &g_data.surfData[i].shaders[j], 0, sizeof( g_data.surfData[i].shaders[j] ) );
  126.         }
  127.     }
  128.     memset (&g_data.model, 0, sizeof(g_data.model));
  129.     memset (g_cddir, 0, sizeof(g_cddir));
  130.  
  131.     g_modelname[0] = 0;
  132.     g_data.scale_up = 1.0;    
  133.     memset( &g_data.model, 0, sizeof( g_data.model ) );
  134.     VectorCopy (vec3_origin, g_data.adjust);
  135.     g_data.fixedwidth = g_data.fixedheight = 0;
  136.     g_skipmodel = qfalse;
  137. }
  138.  
  139. /*
  140. ** void WriteModelSurface( FILE *modelouthandle, md3SurfaceData_t *pSurfData )
  141. **
  142. ** This routine assumes that the file position has been adjusted
  143. ** properly prior to entry to point at the beginning of the surface.
  144. **
  145. ** Since surface header information is completely relative, we can't
  146. ** just randomly seek to an arbitrary surface location right now.  Is
  147. ** this something we should add?
  148. */
  149. void WriteModelSurface( FILE *modelouthandle, md3SurfaceData_t *pSurfData )
  150. {
  151.     md3Surface_t    *pSurf = &pSurfData->header;
  152.     md3Shader_t        *pShader = pSurfData->shaders;
  153.     baseVertex_t    *pBaseVertex = pSurfData->baseVertexes;
  154.     float            **verts = pSurfData->verts;
  155.  
  156.     short xyznormals[MD3_MAX_VERTS][4];
  157.  
  158.     float base_st[MD3_MAX_VERTS][2];
  159.     md3Surface_t surftemp;
  160.  
  161.     int f, i, j, k;
  162.  
  163.     if ( strstr( pSurf->name, "tag_" ) == pSurf->name )
  164.         return;
  165.  
  166.     //
  167.     // write out the header
  168.     //
  169.     surftemp = *pSurf;
  170.     surftemp.ident = LittleLong( MD3_IDENT );
  171.     surftemp.flags = LittleLong( pSurf->flags );
  172.     surftemp.numFrames = LittleLong( pSurf->numFrames );
  173.     surftemp.numShaders = LittleLong( pSurf->numShaders );
  174.  
  175.     surftemp.ofsShaders = LittleLong( pSurf->ofsShaders );
  176.  
  177.     surftemp.ofsTriangles = LittleLong( pSurf->ofsTriangles );
  178.     surftemp.numTriangles = LittleLong( pSurf->numTriangles );
  179.  
  180.     surftemp.ofsSt = LittleLong( pSurf->ofsSt );
  181.     surftemp.ofsXyzNormals = LittleLong( pSurf->ofsXyzNormals );
  182.     surftemp.ofsEnd = LittleLong( pSurf->ofsEnd );
  183.  
  184.     SafeWrite( modelouthandle, &surftemp, sizeof( surftemp ) );
  185.  
  186.     if ( g_verbose )
  187.     {
  188.         printf( "surface '%s'\n", pSurf->name );
  189.         printf( "...num shaders: %d\n", pSurf->numShaders );
  190.     }
  191.  
  192.     //
  193.     // write out shaders
  194.     //
  195.     for ( i = 0; i < pSurf->numShaders; i++ )
  196.     {
  197.         md3Shader_t shadertemp;
  198.  
  199.         if ( g_verbose )
  200.             printf( "......'%s'\n", pShader[i].name );
  201.  
  202.         shadertemp = pShader[i];
  203.         shadertemp.shaderIndex = LittleLong( shadertemp.shaderIndex );
  204.         SafeWrite( modelouthandle, &shadertemp, sizeof( shadertemp ) );
  205.     }
  206.  
  207.     //
  208.     // write out the triangles
  209.     //
  210.     for ( i = 0 ; i < pSurf->numTriangles ; i++ ) 
  211.     {
  212.         for (j = 0 ; j < 3 ; j++) 
  213.         {
  214.             int ivalue = LittleLong( pSurfData->orderedTriangles[i][j] );
  215.             pSurfData->orderedTriangles[i][j] = ivalue;
  216.         }
  217.     }
  218.  
  219.     SafeWrite( modelouthandle, pSurfData->orderedTriangles, pSurf->numTriangles * sizeof( g_data.surfData[0].orderedTriangles[0] ) );
  220.  
  221.     if ( g_verbose )
  222.     {
  223.         printf( "\n...num verts: %d\n", pSurf->numVerts );
  224.         printf( "...TEX COORDINATES\n" );
  225.     }
  226.  
  227.     //
  228.     // write out the texture coordinates
  229.     //
  230.     for ( i = 0; i < pSurf->numVerts ; i++) {
  231.         base_st[i][0] = LittleFloat( pBaseVertex[i].st[0] );
  232.         base_st[i][1] = LittleFloat( pBaseVertex[i].st[1] );
  233.         if ( g_verbose )
  234.             printf( "......%d: %f,%f\n", i, base_st[i][0], base_st[i][1] );
  235.     }
  236.     SafeWrite( modelouthandle, base_st, pSurf->numVerts * sizeof(base_st[0]));
  237.  
  238.     //
  239.     // write the xyz_normal
  240.     //
  241.     if ( g_verbose )
  242.         printf( "...XYZNORMALS\n" );
  243.     for ( f = 0; f < g_data.model.numFrames; f++ )
  244.     {
  245.         for (j=0 ; j< pSurf->numVerts; j++) 
  246.         {
  247.             short value;
  248.  
  249.             for (k=0 ; k < 3 ; k++) 
  250.             {
  251.                 value = ( short ) ( verts[f][j*6+k] / MD3_XYZ_SCALE );
  252.                 xyznormals[j][k] = LittleShort( value );
  253.             }
  254.             NormalToLatLong( &verts[f][j*6+3], (byte *)&xyznormals[j][3] );
  255.         }
  256.         SafeWrite( modelouthandle, xyznormals, pSurf->numVerts * sizeof( short ) * 4 );
  257.     }
  258. }
  259.  
  260. /*
  261. ** void WriteModelFile( FILE *modelouthandle )
  262. **
  263. ** CHUNK            SIZE
  264. ** header            sizeof( md3Header_t )
  265. ** frames            sizeof( md3Frame_t ) * numFrames
  266. ** tags                sizeof( md3Tag_t ) * numFrames * numTags
  267. ** surfaces            surfaceSum
  268. */
  269. void WriteModelFile( FILE *modelouthandle )
  270. {
  271.     int                f;
  272.     int                i, j;
  273.     md3Header_t        modeltemp;
  274.     long            surfaceSum = 0;
  275.     int                numRealSurfaces = 0;
  276.     int                numFrames = g_data.model.numFrames;
  277.  
  278.     // compute offsets for all surfaces, sum their total size
  279.     for ( i = 0; i < g_data.model.numSurfaces; i++ )
  280.     {
  281.         if ( strstr( g_data.surfData[i].header.name, "tag_" ) != g_data.surfData[i].header.name )
  282.         {
  283.             md3Surface_t *psurf = &g_data.surfData[i].header;
  284.  
  285.             if ( psurf->numTriangles == 0 || psurf->numVerts == 0 )
  286.                 continue;
  287.  
  288.             //
  289.             // the triangle and vertex split threshold is controlled by a parameter
  290.             // to $base, a la $base blah.3ds 1900, where "1900" determines the number
  291.             // of triangles to split on
  292.             //
  293.             else if ( psurf->numVerts > MAX_SURFACE_VERTS )
  294.             {
  295.                 Error( "too many vertices\n" );
  296.             }
  297.  
  298.             psurf->numFrames = numFrames;
  299.  
  300.             psurf->ofsShaders = sizeof( md3Surface_t );
  301.  
  302.             if ( psurf->numTriangles > MAX_SURFACE_TRIS  ) 
  303.             {
  304.                 Error( "too many faces\n" );
  305.             }
  306.  
  307.             psurf->ofsTriangles = psurf->ofsShaders + psurf->numShaders * sizeof( md3Shader_t );
  308.  
  309.             psurf->ofsSt = psurf->ofsTriangles + psurf->numTriangles * sizeof( md3Triangle_t );
  310.             psurf->ofsXyzNormals = psurf->ofsSt + psurf->numVerts * sizeof( md3St_t );
  311.             psurf->ofsEnd = psurf->ofsXyzNormals + psurf->numFrames * psurf->numVerts * ( sizeof( short ) * 4 );
  312.  
  313.             surfaceSum += psurf->ofsEnd;
  314.  
  315.             numRealSurfaces++;
  316.         }
  317.     }
  318.  
  319.     g_data.model.ident = MD3_IDENT;
  320.     g_data.model.version = MD3_VERSION;
  321.  
  322.     g_data.model.ofsFrames = sizeof(md3Header_t);
  323.     g_data.model.ofsTags = g_data.model.ofsFrames + numFrames*sizeof(md3Frame_t);
  324.     g_data.model.ofsSurfaces = g_data.model.ofsTags + numFrames*g_data.model.numTags*sizeof(md3Tag_t);
  325.     g_data.model.ofsEnd = g_data.model.ofsSurfaces + surfaceSum;
  326.  
  327.     //
  328.     // write out the model header
  329.     //
  330.     modeltemp = g_data.model;
  331.     modeltemp.ident = LittleLong( modeltemp.ident );
  332.     modeltemp.version = LittleLong( modeltemp.version );
  333.     modeltemp.numFrames = LittleLong( modeltemp.numFrames );
  334.     modeltemp.numTags = LittleLong( modeltemp.numTags );
  335.     modeltemp.numSurfaces = LittleLong( numRealSurfaces );
  336.     modeltemp.ofsFrames = LittleLong( modeltemp.ofsFrames );
  337.     modeltemp.ofsTags = LittleLong( modeltemp.ofsTags );
  338.     modeltemp.ofsSurfaces = LittleLong( modeltemp.ofsSurfaces );
  339.     modeltemp.ofsEnd = LittleLong( modeltemp.ofsEnd );
  340.  
  341.     SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));
  342.  
  343.     //
  344.     // write out the frames
  345.     //
  346.     for (i=0 ; i < numFrames ; i++) 
  347.     {
  348.         vec3_t tmpVec;
  349.         float maxRadius = 0;
  350.  
  351.         //
  352.         // compute localOrigin and radius
  353.         //
  354.         g_data.frames[i].localOrigin[0] =
  355.         g_data.frames[i].localOrigin[1] =
  356.         g_data.frames[i].localOrigin[2] = 0;
  357.  
  358.         for ( j = 0; j < 8; j++ )
  359.         {
  360.             tmpVec[0] = g_data.frames[i].bounds[(j&1)!=0][0];
  361.             tmpVec[1] = g_data.frames[i].bounds[(j&2)!=0][1];
  362.             tmpVec[2] = g_data.frames[i].bounds[(j&4)!=0][2];
  363.  
  364.             if ( VectorLength( tmpVec ) > maxRadius )
  365.                 maxRadius = VectorLength( tmpVec );
  366.         }
  367.  
  368.         g_data.frames[i].radius = LittleFloat( maxRadius );
  369.  
  370.         // swap
  371.         for (j=0 ; j<3 ; j++) {
  372.             g_data.frames[i].bounds[0][j] = LittleFloat( g_data.frames[i].bounds[0][j] );
  373.             g_data.frames[i].bounds[1][j] = LittleFloat( g_data.frames[i].bounds[1][j] );
  374.             g_data.frames[i].localOrigin[j] = LittleFloat( g_data.frames[i].localOrigin[j] );
  375.         }
  376.     }
  377.     fseek (modelouthandle, g_data.model.ofsFrames, SEEK_SET);
  378.     SafeWrite( modelouthandle, g_data.frames, numFrames * sizeof(g_data.frames[0]) );
  379.  
  380.     //
  381.     // write out the tags
  382.     //
  383.     fseek( modelouthandle, g_data.model.ofsTags, SEEK_SET );
  384.     for (f=0 ; f<g_data.model.numFrames; f++) 
  385.     {
  386.         int t;
  387.  
  388.         for ( t = 0; t < g_data.model.numTags; t++ )
  389.         {
  390.             g_data.tags[f][t].origin[0] = LittleFloat(g_data.tags[f][t].origin[0]);
  391.             g_data.tags[f][t].origin[1] = LittleFloat(g_data.tags[f][t].origin[1]);
  392.             g_data.tags[f][t].origin[2] = LittleFloat(g_data.tags[f][t].origin[2]);
  393.  
  394.             for (j=0 ; j<3 ; j++) 
  395.             {
  396.                 g_data.tags[f][t].axis[0][j] = LittleFloat(g_data.tags[f][t].axis[0][j]);
  397.                 g_data.tags[f][t].axis[1][j] = LittleFloat(g_data.tags[f][t].axis[1][j]);
  398.                 g_data.tags[f][t].axis[2][j] = LittleFloat(g_data.tags[f][t].axis[2][j]);
  399.             }
  400.         }
  401.         SafeWrite( modelouthandle, g_data.tags[f], g_data.model.numTags * sizeof(md3Tag_t) );
  402.     }
  403.  
  404.     //
  405.     // write out the surfaces
  406.     //
  407.     fseek( modelouthandle, g_data.model.ofsSurfaces, SEEK_SET );
  408.     for ( i = 0; i < g_data.model.numSurfaces; i++ )
  409.     {
  410.         WriteModelSurface( modelouthandle, &g_data.surfData[i] );
  411.     }
  412. }
  413.  
  414.  
  415. /*
  416. ===============
  417. FinishModel
  418. ===============
  419. */
  420. void FinishModel ( int type )
  421. {
  422.     FILE        *modelouthandle;
  423.     FILE        *defaultSkinHandle;
  424.     char        name[1024];
  425.     int            i;
  426.  
  427.     if (!g_data.model.numFrames)
  428.         return;
  429.  
  430.     //
  431.     // build generalized triangle strips
  432.     //
  433.     OrderSurfaces();
  434.  
  435.     if ( type == TYPE_PLAYER )
  436.     {
  437.         // write a default skin file with the contents of the
  438.         // surface textures, then clean the surface textures
  439.         // so we don't force those textures to be loaded if
  440.         // an alternate skin was loaded instead
  441.         sprintf( name, "%s%s", writedir, g_modelname );
  442.         *strrchr( name, '.' ) = 0;
  443.         strcat( name, "_default.skin" );
  444.  
  445.         defaultSkinHandle = fopen( name, "wt" );
  446.         for ( i = 0; i < g_data.model.numSurfaces; i++ )
  447.         {
  448.             fprintf( defaultSkinHandle, "%s,%s\n", g_data.surfData[i].header.name, g_data.surfData[i].shaders[0].name );
  449.             g_data.surfData[i].shaders[0].name[0] = 0;
  450.         }
  451.         fclose( defaultSkinHandle );
  452.     }
  453.  
  454.     sprintf (name, "%s%s", writedir, g_modelname);
  455.  
  456.     //
  457.     // copy the model and its shaders to release directory tree 
  458.     // if doing a release build
  459.     //
  460.     if ( g_release ) {
  461.         int            i, j;
  462.         md3SurfaceData_t *pSurf;
  463.  
  464.         ReleaseFile( g_modelname );
  465.  
  466.         for ( i = 0; i < g_data.model.numSurfaces; i++ ) {
  467.             pSurf = &g_data.surfData[i];
  468.             for ( j = 0; j < g_data.model.numSkins; j++ ) {
  469.                 ReleaseShader( pSurf->shaders[j].name );
  470.             }
  471.         }        
  472.         return;
  473.     }
  474.     
  475.     //
  476.     // write the model output file
  477.     //
  478.     printf ("saving to %s\n", name);
  479.     CreatePath (name);
  480.     modelouthandle = SafeOpenWrite (name);
  481.  
  482.     WriteModelFile (modelouthandle);
  483.     
  484.     printf ("%4d surfaces\n", g_data.model.numSurfaces);
  485.     printf ("%4d frames\n", g_data.model.numFrames);
  486.     printf ("%4d tags\n", g_data.model.numTags);
  487.     printf ("file size: %d\n", (int)ftell (modelouthandle) );
  488.     printf ("---------------------\n");
  489.     
  490.     fclose (modelouthandle);
  491. }
  492.  
  493. /*
  494. ** OrderSurfaces
  495. **
  496. ** Reorders triangles in all the surfaces.
  497. */
  498. static void OrderSurfaces( void )
  499. {
  500.     int s;
  501.     extern qboolean g_stripify;
  502.  
  503.     // go through each surface and find best strip/fans possible
  504.     for ( s = 0; s < g_data.model.numSurfaces; s++ )
  505.     {
  506.         int mesh[MD3_MAX_TRIANGLES][3];
  507.         int i;
  508.  
  509.         printf( "stripifying surface %d/%d with %d tris\n", s, g_data.model.numSurfaces, g_data.surfData[s].header.numTriangles );
  510.  
  511.         for ( i = 0; i < g_data.surfData[s].header.numTriangles; i++ )
  512.         {
  513.             mesh[i][0] = g_data.surfData[s].lodTriangles[i][0];
  514.             mesh[i][1] = g_data.surfData[s].lodTriangles[i][1];
  515.             mesh[i][2] = g_data.surfData[s].lodTriangles[i][2];
  516.         }
  517.  
  518.         if ( g_stripify )
  519.         {
  520.             OrderMesh( mesh,                                    // input
  521.                        g_data.surfData[s].orderedTriangles,        // output
  522.                        g_data.surfData[s].header.numTriangles );
  523.         }
  524.         else
  525.         {
  526.             memcpy( g_data.surfData[s].orderedTriangles, mesh, sizeof( int ) * 3 * g_data.surfData[s].header.numTriangles );
  527.         }
  528.     }
  529. }
  530.  
  531.  
  532. /*
  533. ===============================================================
  534.  
  535. BASE FRAME SETUP
  536.  
  537. ===============================================================
  538. */
  539. /*
  540. ============
  541. CopyTrianglesToBaseTriangles
  542.  
  543. ============
  544. */
  545. static void CopyTrianglesToBaseTriangles(triangle_t *ptri, int numtri, baseTriangle_t *bTri )
  546. {
  547.     int            i;
  548. //    int            width, height, iwidth, iheight, swidth;
  549. //    float        s_scale, t_scale;
  550. //    float        scale;
  551. //    vec3_t        mins, maxs;
  552.     float        *pbasevert;
  553.  
  554. /*
  555.     //
  556.     // find bounds of all the verts on the base frame
  557.     //
  558.     ClearBounds (mins, maxs);
  559.     
  560.     for (i=0 ; i<numtri ; i++)
  561.         for (j=0 ; j<3 ; j++)
  562.             AddPointToBounds (ptri[i].verts[j], mins, maxs);
  563.     
  564.     for (i=0 ; i<3 ; i++)
  565.     {
  566.         mins[i] = floor(mins[i]);
  567.         maxs[i] = ceil(maxs[i]);
  568.     }
  569.     
  570.     width = maxs[0] - mins[0];
  571.     height = maxs[2] - mins[2];
  572.  
  573.     if (!g_data.fixedwidth)
  574.     {    // old style
  575.         scale = 8;
  576.         if (width*scale >= 150)
  577.             scale = 150.0 / width;    
  578.         if (height*scale >= 190)
  579.             scale = 190.0 / height;
  580.  
  581.         s_scale = t_scale = scale;
  582.  
  583.         iwidth = ceil(width*s_scale);
  584.         iheight = ceil(height*t_scale);
  585.  
  586.         iwidth += 4;
  587.         iheight += 4;
  588.     }
  589.     else
  590.     {    // new style
  591.         iwidth = g_data.fixedwidth / 2;
  592.         iheight = g_data.fixedheight;
  593.  
  594.         s_scale = (float)(iwidth-4) / width;
  595.         t_scale = (float)(iheight-4) / height;
  596.     }
  597.  
  598.     // make the width a multiple of 4; some hardware requires this, and it ensures
  599.     // dword alignment for each scan
  600.     swidth = iwidth*2;
  601.     g_data.skinwidth = (swidth + 3) & ~3;
  602.     g_data.skinheight = iheight;
  603. */
  604.  
  605.     for (i=0; i<numtri ; i++, ptri++, bTri++)
  606.     {
  607.         int j;
  608.  
  609.         for (j=0 ; j<3 ; j++) 
  610.         {
  611.             pbasevert = ptri->verts[j];
  612.  
  613.             VectorCopy( ptri->verts[j], bTri->v[j].xyz);
  614.             VectorCopy( ptri->normals[j], bTri->v[j].normal );
  615.  
  616.             bTri->v[j].st[0] = ptri->texcoords[j][0];
  617.             bTri->v[j].st[1] = ptri->texcoords[j][1];
  618.         }
  619.     }
  620. }
  621.  
  622. static void BuildBaseFrame( const char *filename, ObjectAnimationFrame_t *pOAF )
  623. {
  624.     baseTriangle_t    *bTri;
  625.     baseVertex_t    *bVert;
  626.     int i, j;
  627.  
  628.     // calculate the base triangles
  629.     for ( i = 0; i < g_data.model.numSurfaces; i++ )
  630.     {
  631.         CopyTrianglesToBaseTriangles( pOAF->surfaces[i]->triangles, 
  632.                                     pOAF->surfaces[i]->numtriangles,
  633.                                     g_data.surfData[i].baseTriangles );
  634.  
  635.         strcpy( g_data.surfData[i].header.name, pOAF->surfaces[i]->name );
  636.  
  637.         g_data.surfData[i].header.numTriangles = pOAF->surfaces[i]->numtriangles;
  638.         g_data.surfData[i].header.numVerts = 0;
  639.  
  640. /*
  641.         if ( strstr( filename, gamedir + 1 ) )
  642.         {
  643.             strcpy( shaderName, strstr( filename, gamedir + 1 ) + strlen( gamedir ) - 1 );
  644.         }
  645.         else
  646.         {
  647.             strcpy( shaderName, filename );
  648.         }
  649.  
  650.         if ( strrchr( shaderName, '/' ) )
  651.             *( strrchr( shaderName, '/' ) + 1 ) = 0;
  652.  
  653.  
  654.         strcpy( shaderName, pOAF->surfaces[i]->materialname );
  655. */
  656.         strcpy( g_data.surfData[i].shaders[g_data.surfData[i].header.numShaders].name, pOAF->surfaces[i]->materialname );
  657.  
  658.         g_data.surfData[i].header.numShaders++;
  659.     }
  660.  
  661.     //
  662.     // compute unique vertices for each polyset
  663.     //
  664.     for ( i = 0; i < g_data.model.numSurfaces; i++ )
  665.     {
  666.         int t;
  667.  
  668.         for ( t = 0; t < pOAF->surfaces[i]->numtriangles; t++ )
  669.         {
  670.             bTri = &g_data.surfData[i].baseTriangles[t];
  671.  
  672.             for (j=0 ; j<3 ; j++)
  673.             {
  674.                 int k;
  675.  
  676.                 bVert = &bTri->v[j];
  677.  
  678.                 // get the xyz index
  679.                 for ( k = 0; k < g_data.surfData[i].header.numVerts; k++ )
  680.                 {
  681.                     if ( ( g_data.surfData[i].baseVertexes[k].st[0] == bVert->st[0] ) &&
  682.                          ( g_data.surfData[i].baseVertexes[k].st[1] == bVert->st[1] ) &&
  683.                          ( VectorCompare (bVert->xyz, g_data.surfData[i].baseVertexes[k].xyz) ) &&
  684.                          ( VectorCompare (bVert->normal, g_data.surfData[i].baseVertexes[k].normal) ) )
  685.                     {
  686.                         break;    // this vertex is already in the base vertex list
  687.                     }
  688.                 }
  689.  
  690.                 if (k == g_data.surfData[i].header.numVerts)    { // new index
  691.                     g_data.surfData[i].baseVertexes[g_data.surfData[i].header.numVerts] = *bVert;
  692.                     g_data.surfData[i].header.numVerts++;
  693.                 }
  694.  
  695.                 bVert->index = k;
  696.  
  697.                 g_data.surfData[i].lodTriangles[t][j] = k;
  698.             }
  699.         }
  700.     }
  701.  
  702.     //
  703.     // find tags
  704.     //
  705.     for ( i = 0; i < g_data.model.numSurfaces; i++ )
  706.     {
  707.         if ( strstr( pOAF->surfaces[i]->name, "tag_" ) == pOAF->surfaces[i]->name )
  708.         {
  709.             if ( pOAF->surfaces[i]->numtriangles != 1 )
  710.             {
  711.                 Error( "tag polysets must consist of only one triangle" );
  712.             }
  713.             if ( strstr( filename, "_flash.md3" ) && !strcmp( pOAF->surfaces[i]->name, "tag_parent" ) )
  714.                 continue;
  715.             printf( "found tag '%s'\n", pOAF->surfaces[i]->name );
  716.             g_data.model.numTags++;
  717.         }
  718.     }
  719.  
  720. }
  721.  
  722. static int LoadModelFile( const char *filename, polyset_t **psets, int *numpolysets )
  723. {
  724.     int            time1;
  725.     char        file1[1024];
  726.     const char            *frameFile;
  727.  
  728.     printf ("---------------------\n");
  729.     if ( filename[1] != ':' )
  730.     {
  731.         frameFile = filename;
  732.         sprintf( file1, "%s/%s", g_cddir, frameFile );
  733.     }
  734.     else
  735.     {
  736.         strcpy( file1, filename );
  737.     }
  738.  
  739.     time1 = FileTime (file1);
  740.     if (time1 == -1)
  741.         Error ("%s doesn't exist", file1);
  742.  
  743.     //
  744.     // load the base triangles
  745.     //
  746.     *psets = Polyset_LoadSets( file1, numpolysets, g_data.maxSurfaceTris );
  747.  
  748.     //
  749.     // snap polysets
  750.     //
  751.     Polyset_SnapSets( *psets, *numpolysets );
  752.  
  753.     if ( strstr( file1, ".3ds" ) || strstr( file1, ".3DS" ) )
  754.         return MD3_TYPE_BASE3DS;
  755.  
  756.     Error( "Unknown model file type" );
  757.  
  758.     return MD3_TYPE_UNKNOWN;
  759. }
  760.  
  761. /*
  762. =================
  763. Cmd_Base
  764. =================
  765. */
  766. void Cmd_Base( void )
  767. {
  768.     char filename[1024];
  769.  
  770.     GetToken( qfalse );
  771.     sprintf( filename, "%s/%s", g_cddir, token );
  772.     LoadBase( filename );
  773. }
  774.  
  775. static void LoadBase( const char *filename )
  776. {
  777.     int numpolysets;
  778.     polyset_t *psets;
  779.     int            i;
  780.     ObjectAnimationFrame_t oaf;
  781.  
  782.     // determine polyset splitting threshold
  783.     if ( TokenAvailable() )
  784.     {
  785.         GetToken( qfalse );
  786.         g_data.maxSurfaceTris = atoi( token );
  787.     }
  788.     else
  789.     {
  790.         g_data.maxSurfaceTris = MAX_SURFACE_TRIS - 1;
  791.     }
  792.  
  793.     g_data.type = LoadModelFile( filename, &psets, &numpolysets );
  794.  
  795.     Polyset_ComputeNormals( psets, numpolysets );
  796.  
  797.     g_data.model.numSurfaces = numpolysets;
  798.  
  799.     memset( &oaf, 0, sizeof( oaf ) );
  800.  
  801.     for ( i = 0; i < numpolysets; i++ )
  802.     {
  803.         oaf.surfaces[i] = &psets[i];
  804.         oaf.numSurfaces = numpolysets;
  805.     }
  806.  
  807.     BuildBaseFrame( filename, &oaf );
  808.  
  809.     free( psets[0].triangles );
  810.     free( psets );
  811. }
  812.  
  813. /*
  814. =================
  815. Cmd_SpriteBase
  816.  
  817. $spritebase xorg yorg width height
  818.  
  819. Generate a single square for the model
  820. =================
  821. */
  822. void Cmd_SpriteBase (void)
  823. {
  824.     float        xl, yl, width, height;
  825.  
  826.     g_data.type = MD3_TYPE_SPRITE;
  827.  
  828.     GetToken (qfalse);
  829.     xl = atof(token);
  830.     GetToken (qfalse);
  831.     yl = atof(token);
  832.     GetToken (qfalse);
  833.     width = atof(token);
  834.     GetToken (qfalse);
  835.     height = atof(token);
  836.  
  837. //    if (g_skipmodel || g_release || g_archive)
  838. //        return;
  839.  
  840.     printf ("---------------------\n");
  841.  
  842.     g_data.surfData[0].verts[0] = ( float * ) calloc( 1, sizeof( float ) * 6 * 4 );
  843.  
  844.     g_data.surfData[0].header.numVerts = 4;
  845.  
  846.     g_data.surfData[0].verts[0][0+0] = 0;
  847.     g_data.surfData[0].verts[0][0+1] = -xl;
  848.     g_data.surfData[0].verts[0][0+2] = yl + height;
  849.  
  850.     g_data.surfData[0].verts[0][0+3] = -1;
  851.     g_data.surfData[0].verts[0][0+4] = 0;
  852.     g_data.surfData[0].verts[0][0+5] = 0;
  853.     g_data.surfData[0].baseVertexes[0].st[0] = 0;
  854.     g_data.surfData[0].baseVertexes[0].st[1] = 0;
  855.  
  856.  
  857.     g_data.surfData[0].verts[0][6+0] = 0;
  858.     g_data.surfData[0].verts[0][6+1] = -xl - width;
  859.     g_data.surfData[0].verts[0][6+2] = yl + height;
  860.     
  861.     g_data.surfData[0].verts[0][6+3] = -1;
  862.     g_data.surfData[0].verts[0][6+4] = 0;
  863.     g_data.surfData[0].verts[0][6+5] = 0;
  864.     g_data.surfData[0].baseVertexes[1].st[0] = 1;
  865.     g_data.surfData[0].baseVertexes[1].st[1] = 0;
  866.  
  867.  
  868.     g_data.surfData[0].verts[0][12+0] = 0;
  869.     g_data.surfData[0].verts[0][12+1] = -xl - width;
  870.     g_data.surfData[0].verts[0][12+2] = yl;
  871.  
  872.     g_data.surfData[0].verts[0][12+3] = -1;
  873.     g_data.surfData[0].verts[0][12+4] = 0;
  874.     g_data.surfData[0].verts[0][12+5] = 0;
  875.     g_data.surfData[0].baseVertexes[2].st[0] = 1;
  876.     g_data.surfData[0].baseVertexes[2].st[1] = 1;
  877.  
  878.  
  879.     g_data.surfData[0].verts[0][18+0] = 0;
  880.     g_data.surfData[0].verts[0][18+1] = -xl;
  881.     g_data.surfData[0].verts[0][18+2] = yl;
  882.  
  883.     g_data.surfData[0].verts[0][18+3] = -1;
  884.     g_data.surfData[0].verts[0][18+4] = 0;
  885.     g_data.surfData[0].verts[0][18+5] = 0;
  886.     g_data.surfData[0].baseVertexes[3].st[0] = 0;
  887.     g_data.surfData[0].baseVertexes[3].st[1] = 1;
  888.  
  889.     g_data.surfData[0].lodTriangles[0][0] = 0;
  890.     g_data.surfData[0].lodTriangles[0][1] = 1;
  891.     g_data.surfData[0].lodTriangles[0][2] = 2;
  892.  
  893.     g_data.surfData[0].lodTriangles[1][0] = 2;
  894.     g_data.surfData[0].lodTriangles[1][1] = 3;
  895.     g_data.surfData[0].lodTriangles[1][2] = 0;
  896.  
  897.     g_data.model.numSurfaces = 1;
  898.  
  899.     g_data.surfData[0].header.numTriangles = 2;
  900.     g_data.surfData[0].header.numVerts = 4;
  901.  
  902.     g_data.model.numFrames = 1;
  903. }
  904.  
  905. /*
  906. ===========================================================================
  907.  
  908.   FRAME GRABBING
  909.  
  910. ===========================================================================
  911. */
  912.  
  913. /*
  914. ===============
  915. GrabFrame
  916. ===============
  917. */
  918. void GrabFrame (const char *frame)
  919. {
  920.     int            i, j, k;
  921.     char        file1[1024];
  922.     md3Frame_t        *fr;
  923.     md3Tag_t        tagParent;
  924.     float        *frameXyz;
  925.     float        *frameNormals;
  926.     const char    *framefile;
  927.     polyset_t        *psets;
  928.     qboolean     parentTagExists = qfalse;
  929.     int             numpolysets;
  930.     int            numtags = 0;
  931.     int            tagcount;
  932.  
  933.     // the frame 'run1' will be looked for as either
  934.     // run.1 or run1.tri, so the new alias sequence save
  935.     // feature an be used
  936.     if ( frame[1] != ':' )
  937.     {
  938. //        framefile = FindFrameFile (frame);
  939.         framefile = frame;
  940.         sprintf (file1, "%s/%s",g_cddir, framefile);
  941.     }
  942.     else
  943.     {
  944.         strcpy( file1, frame );
  945.     }
  946.     printf ("grabbing %s\n", file1);
  947.  
  948.     if (g_data.model.numFrames >= MD3_MAX_FRAMES)
  949.         Error ("model.numFrames >= MD3_MAX_FRAMES");
  950.     fr = &g_data.frames[g_data.model.numFrames];
  951.  
  952.     strcpy (fr->name, frame);
  953.  
  954.     psets = Polyset_LoadSets( file1, &numpolysets, g_data.maxSurfaceTris );
  955.  
  956.     //
  957.     // snap polysets
  958.     //
  959.     Polyset_SnapSets( psets, numpolysets );
  960.  
  961.     //
  962.     // compute vertex normals
  963.     //
  964.     Polyset_ComputeNormals( psets, numpolysets );
  965.  
  966.     //
  967.     // flip everything to compensate for the alias coordinate system
  968.     // and perform global scale and adjust
  969.     //
  970.     for ( i = 0; i < g_data.model.numSurfaces; i++ )
  971.     {
  972.         triangle_t *ptri = psets[i].triangles;
  973.         int t;
  974.  
  975.         for ( t = 0; t < psets[i].numtriangles; t++ )
  976.         {
  977.  
  978.             for ( j = 0; j < 3; j++ )
  979.             {
  980.  
  981.                 // scale and adjust
  982.                 for ( k = 0 ; k < 3 ; k++ ) {
  983.                     ptri[t].verts[j][k] = ptri[t].verts[j][k] * g_data.scale_up +
  984.                         g_data.adjust[k];
  985.  
  986.                     if ( ptri[t].verts[j][k] > 1023 ||
  987.                          ptri[t].verts[j][k] < -1023 )
  988.                     {
  989.                         Error( "Model extents too large" );
  990.                     }
  991.                 }
  992.             }
  993.         }
  994.     }
  995.  
  996.     //
  997.     // find and count tags, locate parent tag
  998.     //
  999.     for ( i = 0; i < numpolysets; i++ )
  1000.     {
  1001.         if ( strstr( psets[i].name, "tag_" ) == psets[i].name )
  1002.         {
  1003.             if ( strstr( psets[i].name, "tag_parent" ) == psets[i].name )
  1004.             {
  1005.                 if ( strstr( psets[i].name, "tag_parent" ) )
  1006.                 {
  1007.                     float tri[3][3];
  1008.  
  1009.                     if ( parentTagExists )
  1010.                         Error( "Multiple parent tags not allowed" );
  1011.  
  1012.                     memcpy( tri[0], psets[i].triangles[0].verts[0], sizeof( float ) * 3 );
  1013.                     memcpy( tri[1], psets[i].triangles[0].verts[1], sizeof( float ) * 3 );
  1014.                     memcpy( tri[2], psets[i].triangles[0].verts[2], sizeof( float ) * 3 );
  1015.  
  1016.                     MD3_ComputeTagFromTri( &tagParent, tri );
  1017.                     strcpy( tagParent.name, psets[i].name );
  1018.                     g_data.tags[g_data.model.numFrames][numtags] = tagParent;
  1019.                     parentTagExists = qtrue;
  1020.  
  1021.                 }
  1022.             }
  1023.             numtags++;
  1024.         }
  1025.  
  1026.         if ( strcmp( psets[i].name, g_data.surfData[i].header.name ) )
  1027.         {
  1028.             Error( "Mismatched surfaces from base('%s') to frame('%s') in model '%s'\n", g_data.surfData[i].header.name, psets[i].name, g_modelname );
  1029.         }
  1030.     }
  1031.  
  1032.     if ( numtags != g_data.model.numTags )
  1033.     {
  1034.         Error( "mismatched number of tags in frame(%d) vs. base(%d)", numtags, g_data.model.numTags );
  1035.     }
  1036.  
  1037.     if ( numpolysets != g_data.model.numSurfaces )
  1038.     {
  1039.         Error( "mismatched number of surfaces in frame(%d) vs. base(%d)", numpolysets-numtags, g_data.model.numSurfaces );
  1040.     }
  1041.     
  1042.     //
  1043.     // prepare to accumulate bounds and normals
  1044.     //
  1045.     ClearBounds( fr->bounds[0], fr->bounds[1] );
  1046.  
  1047.     //
  1048.     // store the frame's vertices in the same order as the base. This assumes the
  1049.     // triangles and vertices in this frame are in exactly the same order as in the
  1050.     // base
  1051.     //
  1052.     for ( i = 0, tagcount = 0; i < numpolysets; i++ )
  1053.     {
  1054.         int t;
  1055.         triangle_t *pTris = psets[i].triangles;
  1056.  
  1057.         strcpy( g_data.surfData[i].header.name, psets[i].name );
  1058.  
  1059.         //
  1060.         // parent tag adjust
  1061.         //
  1062.         if ( parentTagExists ) {
  1063.             for ( t = 0; t < psets[i].numtriangles; t++ )
  1064.             {
  1065.                 for ( j = 0; j < 3 ; j++ )
  1066.                 {
  1067.                     vec3_t tmp;
  1068.                     
  1069.                     VectorSubtract( pTris[t].verts[j], tagParent.origin, tmp );
  1070.  
  1071.                     pTris[t].verts[j][0] = DotProduct( tmp, tagParent.axis[0] );
  1072.                     pTris[t].verts[j][1] = DotProduct( tmp, tagParent.axis[1] );
  1073.                     pTris[t].verts[j][2] = DotProduct( tmp, tagParent.axis[2] );
  1074.  
  1075.                     VectorCopy( pTris[t].normals[j], tmp );
  1076.                     pTris[t].normals[j][0] = DotProduct( tmp, tagParent.axis[0] );
  1077.                     pTris[t].normals[j][1] = DotProduct( tmp, tagParent.axis[1] );
  1078.                     pTris[t].normals[j][2] = DotProduct( tmp, tagParent.axis[2] );
  1079.                 }
  1080.             }
  1081.         }
  1082.  
  1083.         //
  1084.         // compute tag data
  1085.         //
  1086.         if ( strstr( psets[i].name, "tag_" ) == psets[i].name )
  1087.         {
  1088.             md3Tag_t *pTag = &g_data.tags[g_data.model.numFrames][tagcount];
  1089.             float tri[3][3];
  1090.  
  1091.             strcpy( pTag->name, psets[i].name );
  1092.  
  1093.             memcpy( tri[0], pTris[0].verts[0], sizeof( float ) * 3 );
  1094.             memcpy( tri[1], pTris[0].verts[1], sizeof( float ) * 3 );
  1095.             memcpy( tri[2], pTris[0].verts[2], sizeof( float ) * 3 );
  1096.  
  1097.             MD3_ComputeTagFromTri( pTag, tri );
  1098.             tagcount++;
  1099.         }
  1100.         else
  1101.         {
  1102.             if ( g_data.surfData[i].verts[g_data.model.numFrames] )
  1103.                 free( g_data.surfData[i].verts[g_data.model.numFrames] );
  1104.             frameXyz = g_data.surfData[i].verts[g_data.model.numFrames] = calloc( 1, sizeof( float ) * 6 * g_data.surfData[i].header.numVerts );
  1105.             frameNormals = frameXyz + 3;
  1106.  
  1107.             for ( t = 0; t < psets[i].numtriangles; t++ )
  1108.             {
  1109.                 for ( j = 0; j < 3 ; j++ )
  1110.                 {
  1111.                     int index;
  1112.  
  1113.                     index = g_data.surfData[i].baseTriangles[t].v[j].index;
  1114.                     frameXyz[index*6+0] = pTris[t].verts[j][0];
  1115.                     frameXyz[index*6+1] = pTris[t].verts[j][1];
  1116.                     frameXyz[index*6+2] = pTris[t].verts[j][2];
  1117.                     frameNormals[index*6+0] =  pTris[t].normals[j][0];
  1118.                     frameNormals[index*6+1] =  pTris[t].normals[j][1];
  1119.                     frameNormals[index*6+2] =  pTris[t].normals[j][2];
  1120.                     AddPointToBounds (&frameXyz[index*6], fr->bounds[0], fr->bounds[1] );
  1121.                 }
  1122.             }
  1123.         }
  1124.     }
  1125.  
  1126.     g_data.model.numFrames++;
  1127.  
  1128.     // only free the first triangle array, all of the psets in this array share the
  1129.     // same triangle pool!!!
  1130. //    free( psets[0].triangles );
  1131. //    free( psets );
  1132. }
  1133.  
  1134. //===========================================================================
  1135.  
  1136.  
  1137.  
  1138. /*
  1139. ===============
  1140. Cmd_Frame    
  1141. ===============
  1142. */
  1143. void Cmd_Frame (void)
  1144. {
  1145.     while (TokenAvailable())
  1146.     {
  1147.         GetToken (qfalse);
  1148.         if (g_skipmodel)
  1149.             continue;
  1150.         if (g_release || g_archive)
  1151.         {
  1152.             g_data.model.numFrames = 1;    // don't skip the writeout
  1153.             continue;
  1154.         }
  1155.  
  1156.         GrabFrame( token );
  1157.     }
  1158. }
  1159.  
  1160.  
  1161. /*
  1162. ===============
  1163. Cmd_Skin
  1164.  
  1165. ===============
  1166. */
  1167. void SkinFrom3DS( const char *filename )
  1168. {
  1169.     polyset_t *psets;
  1170.     char name[1024];
  1171.     int numPolysets;
  1172.     int i;
  1173.  
  1174.     _3DS_LoadPolysets( filename, &psets, &numPolysets, g_verbose );
  1175.  
  1176.     for ( i = 0; i < numPolysets; i++ )
  1177.     {
  1178. /*
  1179.         if ( strstr( filename, gamedir + 1 ) )
  1180.         {
  1181.             strcpy( name, strstr( filename, gamedir + 1 ) + strlen( gamedir ) - 1 );
  1182.         }
  1183.         else
  1184.         {
  1185.             strcpy( name, filename );
  1186.         }
  1187.  
  1188.         if ( strrchr( name, '/' ) )
  1189.             *( strrchr( name, '/' ) + 1 ) = 0;
  1190. */
  1191.         strcpy( name, psets[i].materialname );
  1192.         strcpy( g_data.surfData[i].shaders[g_data.surfData[i].header.numShaders].name, name );
  1193.  
  1194.         g_data.surfData[i].header.numShaders++;
  1195.     }
  1196.  
  1197.     free( psets[0].triangles );
  1198.     free( psets );
  1199. }
  1200.  
  1201. void Cmd_Skin (void)
  1202. {
  1203.     char skinfile[1024];
  1204.  
  1205.     if ( g_data.type == MD3_TYPE_BASE3DS )
  1206.     {
  1207.         GetToken( qfalse );
  1208.  
  1209.         sprintf( skinfile, "%s/%s", g_cddir, token );
  1210.  
  1211.         if ( strstr( token, ".3ds" ) || strstr( token, ".3DS" ) )
  1212.         {
  1213.             SkinFrom3DS( skinfile );
  1214.         }
  1215.         else
  1216.         {
  1217.             Error( "Unknown file format for $skin '%s'\n", skinfile );
  1218.         }
  1219.     }
  1220.     else
  1221.     {
  1222.         Error( "invalid model type while processing $skin" );
  1223.     }
  1224.  
  1225.     g_data.model.numSkins++;
  1226. }
  1227.  
  1228. /*
  1229. =================
  1230. Cmd_SpriteShader
  1231. =================
  1232.  
  1233. This routine is also called for $oldskin
  1234.  
  1235. */
  1236. void Cmd_SpriteShader()
  1237. {
  1238.     GetToken( qfalse );
  1239.     strcpy( g_data.surfData[0].shaders[g_data.surfData[0].header.numShaders].name, token );
  1240.     g_data.surfData[0].header.numShaders++;
  1241.     g_data.model.numSkins++;
  1242. }
  1243.  
  1244. /*
  1245. =================
  1246. Cmd_Origin
  1247. =================
  1248. */
  1249. void Cmd_Origin (void)
  1250. {
  1251.     // rotate points into frame of reference so model points down the
  1252.     // positive x axis
  1253.     // FIXME: use alias native coordinate system
  1254.     GetToken (qfalse);
  1255.     g_data.adjust[1] = -atof (token);
  1256.  
  1257.     GetToken (qfalse);
  1258.     g_data.adjust[0] = atof (token);
  1259.  
  1260.     GetToken (qfalse);
  1261.     g_data.adjust[2] = -atof (token);
  1262. }
  1263.  
  1264.  
  1265. /*
  1266. =================
  1267. Cmd_ScaleUp
  1268. =================
  1269. */
  1270. void Cmd_ScaleUp (void)
  1271. {
  1272.     GetToken (qfalse);
  1273.     g_data.scale_up = atof (token);
  1274.     if (g_skipmodel || g_release || g_archive)
  1275.         return;
  1276.  
  1277.     printf ("Scale up: %f\n", g_data.scale_up);
  1278. }
  1279.  
  1280.  
  1281. /*
  1282. =================
  1283. Cmd_Skinsize
  1284.  
  1285. Set a skin size other than the default
  1286. QUAKE3: not needed
  1287. =================
  1288. */
  1289. void Cmd_Skinsize (void)
  1290. {
  1291.     GetToken (qfalse);
  1292.     g_data.fixedwidth = atoi(token);
  1293.     GetToken (qfalse);
  1294.     g_data.fixedheight = atoi(token);
  1295. }
  1296.  
  1297. /*
  1298. =================
  1299. Cmd_Modelname
  1300.  
  1301. Begin creating a model of the given name
  1302. =================
  1303. */
  1304. void Cmd_Modelname (void)
  1305. {
  1306.     FinishModel ( TYPE_UNKNOWN );
  1307.     ClearModel ();
  1308.  
  1309.     GetToken (qfalse);
  1310.     strcpy (g_modelname, token);
  1311.     StripExtension (g_modelname);
  1312.     strcat (g_modelname, ".md3");
  1313.     strcpy (g_data.model.name, g_modelname);
  1314. }
  1315.  
  1316. /*
  1317. ===============
  1318. fCmd_Cd
  1319. ===============
  1320. */
  1321. void Cmd_Cd (void)
  1322. {
  1323.     if ( g_cddir[0]) {
  1324.         Error ("$cd command without a $modelname");
  1325.     }
  1326.  
  1327.     GetToken (qfalse);
  1328.  
  1329.     sprintf ( g_cddir, "%s%s", gamedir, token);
  1330.  
  1331.     // if -only was specified and this cd doesn't match,
  1332.     // skip the model (you only need to match leading chars,
  1333.     // so you could regrab all monsters with -only models/monsters)
  1334.     if (!g_only[0])
  1335.         return;
  1336.     if (strncmp(token, g_only, strlen(g_only)))
  1337.     {
  1338.         g_skipmodel = qtrue;
  1339.         printf ("skipping %s\n", token);
  1340.     }
  1341. }
  1342.  
  1343. void Convert3DStoMD3( const char *file )
  1344. {
  1345.     LoadBase( file );
  1346.     GrabFrame( file );
  1347.     SkinFrom3DS( file );
  1348.  
  1349.     strcpy( g_data.model.name, g_modelname );
  1350.  
  1351.     FinishModel( TYPE_UNKNOWN );
  1352.     ClearModel();
  1353. }
  1354.  
  1355. /*
  1356. ** Cmd_3DSConvert
  1357. */
  1358. void Cmd_3DSConvert()
  1359. {
  1360.     char file[1024];
  1361.  
  1362.     FinishModel( TYPE_UNKNOWN );
  1363.     ClearModel();
  1364.  
  1365.     GetToken( qfalse );
  1366.  
  1367.     sprintf( file, "%s%s", gamedir, token );
  1368.     strcpy( g_modelname, token );
  1369.     if ( strrchr( g_modelname, '.' ) )
  1370.         *strrchr( g_modelname, '.' ) = 0;
  1371.     strcat( g_modelname, ".md3" );
  1372.  
  1373.     if ( FileTime( file ) == -1 )
  1374.         Error( "%s doesn't exist", file );
  1375.  
  1376.     if ( TokenAvailable() )
  1377.     {
  1378.         GetToken( qfalse );
  1379.         g_data.scale_up = atof( token );
  1380.     }
  1381.  
  1382.     Convert3DStoMD3( file );
  1383. }
  1384.  
  1385. static void ConvertASE( const char *filename, int type, qboolean grabAnims );
  1386.  
  1387. /*
  1388. ** Cmd_ASEConvert
  1389. */
  1390. void Cmd_ASEConvert( qboolean grabAnims )
  1391. {
  1392.     char filename[1024];
  1393.     int type = TYPE_ITEM;
  1394.  
  1395.     FinishModel( TYPE_UNKNOWN );
  1396.     ClearModel();
  1397.  
  1398.     GetToken( qfalse );
  1399.     sprintf( filename, "%s%s", gamedir, token );
  1400.  
  1401.     strcpy (g_modelname, token);
  1402.     StripExtension (g_modelname);
  1403.     strcat (g_modelname, ".md3");
  1404.     strcpy (g_data.model.name, g_modelname);
  1405.  
  1406.     if ( !strstr( filename, ".ase" ) && !strstr( filename, ".ASE" ) )
  1407.         strcat( filename, ".ASE" );
  1408.  
  1409.     g_data.maxSurfaceTris = MAX_SURFACE_TRIS - 1;
  1410.  
  1411.     while ( TokenAvailable() )
  1412.     {
  1413.         GetToken( qfalse );
  1414.         if ( !strcmp( token, "-offset" ) )
  1415.         {
  1416.             if ( !TokenAvailable() )
  1417.                 Error( "missing parameter for -offset" );
  1418.             GetToken( qfalse );
  1419.             g_data.aseAdjust[1] = -atof( token );
  1420.  
  1421.             if ( !TokenAvailable() )
  1422.                 Error( "missing parameter for -offset" );
  1423.             GetToken( qfalse );
  1424.             g_data.aseAdjust[0] = atof (token);
  1425.  
  1426.             if ( !TokenAvailable() )
  1427.                 Error( "missing parameter for -offset" );
  1428.             GetToken( qfalse );
  1429.             g_data.aseAdjust[2] = -atof (token);
  1430.         }
  1431.         else if ( !strcmp( token, "-lod" ) )
  1432.         {
  1433.             if ( !TokenAvailable() )
  1434.                 Error( "No parameter for -lod" );
  1435.             GetToken( qfalse );
  1436.             g_data.currentLod = atoi( token );
  1437.             if ( g_data.currentLod > MD3_MAX_LODS - 1 )
  1438.             {
  1439.                 Error( "-lod parameter too large! (%d)\n", g_data.currentLod );
  1440.             }
  1441. #if 0
  1442.             if ( !TokenAvailable() )
  1443.                 Error( "No second parameter for -lod" );
  1444.             GetToken( qfalse );
  1445.             g_data.lodBias = atof( token );
  1446. #endif
  1447.         }
  1448.         else if ( !strcmp( token, "-maxtris" ) )
  1449.         {
  1450.             if ( !TokenAvailable() )
  1451.                 Error( "No parameter for -maxtris" );
  1452.             GetToken( qfalse );
  1453.             g_data.maxSurfaceTris = atoi( token );
  1454.         }
  1455.         else if ( !strcmp( token, "-playerparms" ) )
  1456.         {
  1457.             if ( !TokenAvailable() )
  1458.                 Error( "missing skip start parameter for -playerparms" );
  1459.             GetToken( qfalse );
  1460.             g_data.lowerSkipFrameStart = atoi( token );
  1461.  
  1462.             if ( !TokenAvailable() )
  1463.                 Error( "missing upper parameter for -playerparms" );
  1464.             GetToken( qfalse );
  1465.             g_data.maxUpperFrames = atoi( token );
  1466.  
  1467.             g_data.lowerSkipFrameEnd = g_data.maxUpperFrames - 1;
  1468.  
  1469.             g_data.maxHeadFrames = 1;
  1470.  
  1471.             if ( type != TYPE_ITEM )
  1472.                 Error( "invalid argument" );
  1473.  
  1474.             // set default player origin offsets
  1475.             // this is sort of a historic artifact...
  1476.             g_data.aseAdjust[1] = 0;
  1477.             g_data.aseAdjust[0] = 0;
  1478.             g_data.aseAdjust[2] = -24;
  1479.  
  1480.  
  1481.             type = TYPE_PLAYER;
  1482.         }
  1483.         else if ( !strcmp( token, "-weapon" ) )
  1484.         {
  1485.             if ( type != TYPE_ITEM )
  1486.                 Error( "invalid argument" );
  1487.  
  1488.             type = TYPE_WEAPON;
  1489.         }
  1490.     }
  1491.  
  1492.     g_data.type = MD3_TYPE_ASE;
  1493.  
  1494.     if ( type == TYPE_WEAPON && grabAnims )
  1495.     {
  1496.         Error( "can't grab anims with weapon models" );
  1497.     }
  1498.     if ( type == TYPE_PLAYER && !grabAnims )
  1499.     {
  1500.         Error( "player models must be converted with $aseanimconvert" );
  1501.     }
  1502.  
  1503.     if ( type == TYPE_WEAPON )
  1504.     {
  1505.         ConvertASE( filename, type, qfalse );
  1506.         ConvertASE( filename, TYPE_HAND, qtrue );
  1507.     }
  1508.     else
  1509.     {
  1510.         ConvertASE( filename, type, grabAnims );
  1511.     }
  1512. }
  1513.  
  1514. static int GetSurfaceAnimations( SurfaceAnimation_t sanims[MAX_ANIM_SURFACES], 
  1515.                                   const char *part,
  1516.                                   int skipFrameStart,
  1517.                                   int skipFrameEnd,
  1518.                                   int maxFrames )
  1519.  
  1520. {
  1521.     int numSurfaces;
  1522.     int numValidSurfaces;
  1523.     int i;
  1524.     int numFrames = -1;
  1525.  
  1526.     if ( ( numSurfaces = ASE_GetNumSurfaces() ) > MAX_ANIM_SURFACES )
  1527.     {
  1528.         Error( "Too many surfaces in ASE" );
  1529.     }
  1530.  
  1531.     for ( numValidSurfaces = 0, i = 0; i < numSurfaces; i++ )
  1532.     {
  1533.         polyset_t *splitSets;
  1534.         int numNewFrames;
  1535.         const char *surfaceName = ASE_GetSurfaceName( i );
  1536.  
  1537.         if ( !surfaceName )
  1538.         {
  1539.             continue;
  1540. //            Error( "Missing animation frames in model" );
  1541.         }
  1542.  
  1543.         if ( strstr( surfaceName, "tag_" ) || 
  1544.              !strcmp( part, "any" ) || 
  1545.              ( strstr( surfaceName, part ) == surfaceName ) )
  1546.         {
  1547.  
  1548.             // skip this if it's an inappropriate tag
  1549.             if ( strcmp( part, "any" ) )
  1550.             {
  1551.                 // ignore non-"tag_head" tags if this is the head
  1552.                 if ( !strcmp( part, "h_" ) && strstr( surfaceName, "tag_" ) && strcmp( surfaceName, "tag_head" ) )
  1553.                     continue;
  1554.                 // ignore "tag_head" if this is the legs
  1555.                 if ( !strcmp( part, "l_" ) && !strcmp( surfaceName, "tag_head" ) )
  1556.                     continue;
  1557.                 // ignore "tag_weapon" if this is the legs
  1558.                 if ( !strcmp( part, "l_" ) && !strcmp( surfaceName, "tag_weapon" ) )
  1559.                     continue;
  1560.             }
  1561.  
  1562.             if ( ( sanims[numValidSurfaces].frames = ASE_GetSurfaceAnimation( i, &sanims[numValidSurfaces].numFrames, skipFrameStart, skipFrameEnd, maxFrames ) ) != 0 )
  1563.             {
  1564.                 splitSets = Polyset_SplitSets( sanims[numValidSurfaces].frames, sanims[numValidSurfaces].numFrames, &numNewFrames, g_data.maxSurfaceTris );
  1565.                 
  1566.                 if ( numFrames == -1 )
  1567.                     numFrames = sanims[numValidSurfaces].numFrames;
  1568.                 else if ( numFrames != sanims[numValidSurfaces].numFrames )
  1569.                     Error( "Different number of animation frames on surfaces" );
  1570.                 
  1571.                 if ( sanims[numValidSurfaces].frames != splitSets )
  1572.                 {
  1573.                     int j;
  1574.  
  1575.                     // free old data if we split the surfaces
  1576.                     for ( j = 0; j < sanims[numValidSurfaces].numFrames; j++ )
  1577.                     {
  1578.                         free( sanims[numValidSurfaces].frames[j].triangles );
  1579.                         free( sanims[numValidSurfaces].frames );
  1580.                     }
  1581.                     
  1582.                     sanims[numValidSurfaces].frames = splitSets;
  1583.                     sanims[numValidSurfaces].numFrames = numNewFrames;
  1584.                 }
  1585.                 Polyset_SnapSets( sanims[numValidSurfaces].frames, sanims[numValidSurfaces].numFrames );
  1586.                 Polyset_ComputeNormals( sanims[numValidSurfaces].frames, sanims[numValidSurfaces].numFrames );
  1587.  
  1588.                 numValidSurfaces++;
  1589.             }
  1590.         }
  1591.     }
  1592.  
  1593.     return numValidSurfaces;
  1594. }
  1595.  
  1596. static int SurfaceOrderToFrameOrder( SurfaceAnimation_t sanims[], ObjectAnimationFrame_t oanims[], int numSurfaces )
  1597. {
  1598.     int i, s;
  1599.     int numFrames = -1;
  1600.  
  1601.     /*
  1602.     ** we have the data here arranged in surface order, now we need to convert it to 
  1603.     ** frame order
  1604.     */
  1605.     for ( i = 0, s = 0; i < numSurfaces; i++ )
  1606.     {
  1607.         int j;
  1608.         
  1609.         if ( sanims[i].frames )
  1610.         {
  1611.             if ( numFrames == -1 )
  1612.                 numFrames = sanims[i].numFrames;
  1613.             else if ( numFrames != sanims[i].numFrames )
  1614.                 Error( "numFrames != sanims[i].numFrames (%d != %d)\n", numFrames, sanims[i].numFrames );
  1615.  
  1616.             for ( j = 0; j < sanims[i].numFrames; j++ )
  1617.             {
  1618.                 oanims[j].surfaces[s] = &sanims[i].frames[j];
  1619.                 oanims[j].numSurfaces = numSurfaces;
  1620.             }
  1621.             s++;
  1622.         }
  1623.     }
  1624.  
  1625.     return numFrames;
  1626. }
  1627.  
  1628. static void WriteMD3( const char *_filename, ObjectAnimationFrame_t oanims[], int numFrames )
  1629. {
  1630.     char filename[1024];
  1631.  
  1632.     strcpy( filename, _filename );
  1633.     if ( strchr( filename, '.' ) )
  1634.         *strchr( filename, '.' ) = 0;
  1635.     strcat( filename, ".md3" );
  1636. }
  1637.  
  1638. static void BuildAnimationFromOAFs( const char *filename, ObjectAnimationFrame_t oanims[], int numFrames, int type )
  1639. {
  1640.     int f, i, j, tagcount;
  1641.     float *frameXyz;
  1642.     float *frameNormals;
  1643.  
  1644.     g_data.model.numSurfaces = oanims[0].numSurfaces;
  1645.     g_data.model.numFrames = numFrames;
  1646.     if ( g_data.model.numFrames < 0)
  1647.         Error ("model.numFrames < 0");
  1648.     if ( g_data.model.numFrames >= MD3_MAX_FRAMES)
  1649.         Error ("model.numFrames >= MD3_MAX_FRAMES");
  1650.  
  1651.     // build base frame
  1652.     BuildBaseFrame( filename, &oanims[0] );
  1653.     
  1654.     // build animation frames
  1655.     for ( f = 0; f < numFrames; f++ )
  1656.     {
  1657.         ObjectAnimationFrame_t *pOAF = &oanims[f];
  1658.         qboolean    parentTagExists = qfalse;
  1659.         md3Tag_t    tagParent;
  1660.         int            numtags = 0;
  1661.         md3Frame_t        *fr;
  1662.         
  1663.         fr = &g_data.frames[f];
  1664.         
  1665.         strcpy( fr->name, "(from ASE)" );
  1666.         
  1667.         // scale and adjust frame
  1668.         for ( i = 0; i < pOAF->numSurfaces; i++ )
  1669.         {
  1670.             triangle_t *pTris = pOAF->surfaces[i]->triangles;
  1671.             int t;
  1672.             
  1673.             for ( t = 0; t < pOAF->surfaces[i]->numtriangles; t++ )
  1674.             {
  1675.                 for ( j = 0; j < 3; j++ )
  1676.                 {
  1677.                     int k;
  1678.                     
  1679.                     // scale and adjust
  1680.                     for ( k = 0 ; k < 3 ; k++ ) {
  1681.                         pTris[t].verts[j][k] = pTris[t].verts[j][k] * g_data.scale_up +
  1682.                             g_data.aseAdjust[k];
  1683.                         
  1684.                         if ( pTris[t].verts[j][k] > 1023 ||
  1685.                             pTris[t].verts[j][k] < -1023 )
  1686.                         {
  1687.                             Error( "Model extents too large" );
  1688.                         }
  1689.                     }
  1690.                 }
  1691.             }
  1692.         }
  1693.         
  1694.         //
  1695.         // find and count tags, locate parent tag
  1696.         //
  1697.         for ( i = 0; i < pOAF->numSurfaces; i++ )
  1698.         {
  1699.             if ( strstr( pOAF->surfaces[i]->name, "tag_" ) != pOAF->surfaces[i]->name )
  1700.             {
  1701.                 // not a tag, make sure the surface name matches
  1702.                 if ( strcmp( pOAF->surfaces[i]->name, g_data.surfData[i].header.name ) )
  1703.                 {
  1704.                     Error( "Mismatched surfaces from base('%s') to frame('%s') in model '%s'\n", g_data.surfData[i].header.name, pOAF->surfaces[i]->name, filename );
  1705.                 }
  1706.                 continue;
  1707.             }
  1708.  
  1709.             // ignore parent tags when grabbing a weapon model and this is the flash portion
  1710.             if ( !strcmp( pOAF->surfaces[i]->name, "tag_parent" ) && strstr( filename, "_flash" ) )
  1711.             {
  1712.                 continue;
  1713.             }
  1714.             if ( !strcmp( pOAF->surfaces[i]->name, "tag_parent" ) && strstr( filename, "_barrel" ) )
  1715.             {
  1716.                 continue;
  1717.             }
  1718.  
  1719.             // see if this should be the parent for this set of surfaces
  1720.             if ( !strstr( filename, "_hand.md3" ) && (
  1721.                  ( !strcmp( pOAF->surfaces[i]->name, "tag_parent" ) ) ||
  1722.                  ( !strcmp( pOAF->surfaces[i]->name, "tag_torso" ) && strstr( filename, "upper" ) ) ||
  1723.                  ( !strcmp( pOAF->surfaces[i]->name, "tag_head" ) && strstr( filename, "head" ) ) ||
  1724.                  ( !strcmp( pOAF->surfaces[i]->name, "tag_flash" ) && strstr( filename, "flash" ) ) || 
  1725.                  ( !strcmp( pOAF->surfaces[i]->name, "tag_barrel" ) && strstr( filename, "barrel" ) ) || 
  1726.                  ( !strcmp( pOAF->surfaces[i]->name, "tag_weapon" ) && type == TYPE_WEAPON ) ) )
  1727.             {
  1728.                 float tri[3][3];
  1729.                 
  1730.                 if ( parentTagExists )
  1731.                     Error( "Multiple parent tags not allowed" );
  1732.                 
  1733.                 memcpy( tri[0], pOAF->surfaces[i]->triangles[0].verts[0], sizeof( float ) * 3 );
  1734.                 memcpy( tri[1], pOAF->surfaces[i]->triangles[0].verts[1], sizeof( float ) * 3 );
  1735.                 memcpy( tri[2], pOAF->surfaces[i]->triangles[0].verts[2], sizeof( float ) * 3 );
  1736.                 
  1737.                 MD3_ComputeTagFromTri( &tagParent, tri );
  1738.                 strcpy( tagParent.name, "tag_parent" );
  1739.                 g_data.tags[f][numtags] = tagParent;
  1740.                 parentTagExists = qtrue;
  1741.             }
  1742.             else
  1743.             {
  1744.                 float tri[3][3];
  1745.             
  1746.                 // this is just another tag we will store in the model for attaching other things
  1747.                 memcpy( tri[0], pOAF->surfaces[i]->triangles[0].verts[0], sizeof( float ) * 3 );
  1748.                 memcpy( tri[1], pOAF->surfaces[i]->triangles[0].verts[1], sizeof( float ) * 3 );
  1749.                 memcpy( tri[2], pOAF->surfaces[i]->triangles[0].verts[2], sizeof( float ) * 3 );
  1750.                 
  1751.                 MD3_ComputeTagFromTri( &g_data.tags[f][numtags], tri );
  1752.                 strcpy( g_data.tags[f][numtags].name, pOAF->surfaces[i]->name );
  1753.                 if ( strstr( g_data.tags[f][numtags].name, "tag_flash" ) )
  1754.                     * ( strstr( g_data.tags[f][numtags].name, "tag_flash" ) + strlen( "tag_flash" ) ) = 0;
  1755.             }
  1756.  
  1757.             numtags++;
  1758.         }
  1759.         
  1760.         if ( numtags != g_data.model.numTags )
  1761.         {
  1762.             Error( "mismatched number of tags in frame(%d) vs. base(%d)", numtags, g_data.model.numTags );
  1763.         }
  1764.         
  1765.         //
  1766.         // prepare to accumulate bounds and normals
  1767.         //
  1768.         ClearBounds( fr->bounds[0], fr->bounds[1] );
  1769.         
  1770.         //
  1771.         // store the frame's vertices in the same order as the base. This assumes the
  1772.         // triangles and vertices in this frame are in exactly the same order as in the
  1773.         // base
  1774.         //
  1775.         for ( i = 0, tagcount = 0; i < pOAF->numSurfaces; i++ )
  1776.         {
  1777.             int t;
  1778.             triangle_t *pTris = pOAF->surfaces[i]->triangles;
  1779.             
  1780.             //
  1781.             // parent tag adjust
  1782.             //
  1783.             if ( parentTagExists ) 
  1784.             {
  1785.                 for ( t = 0; t < pOAF->surfaces[i]->numtriangles; t++ )
  1786.                 {
  1787.                     for ( j = 0; j < 3 ; j++ )
  1788.                     {
  1789.                         vec3_t tmp;
  1790.                         
  1791.                         VectorSubtract( pTris[t].verts[j], tagParent.origin, tmp );
  1792.                         
  1793.                         pTris[t].verts[j][0] = DotProduct( tmp, tagParent.axis[0] );
  1794.                         pTris[t].verts[j][1] = DotProduct( tmp, tagParent.axis[1] );
  1795.                         pTris[t].verts[j][2] = DotProduct( tmp, tagParent.axis[2] );
  1796.                         
  1797.                         VectorCopy( pTris[t].normals[j], tmp );
  1798.                         pTris[t].normals[j][0] = DotProduct( tmp, tagParent.axis[0] );
  1799.                         pTris[t].normals[j][1] = DotProduct( tmp, tagParent.axis[1] );
  1800.                         pTris[t].normals[j][2] = DotProduct( tmp, tagParent.axis[2] );
  1801.                     }
  1802.                 }
  1803.             }
  1804.             
  1805.             //
  1806.             // compute tag data
  1807.             //
  1808.             if ( strstr( pOAF->surfaces[i]->name, "tag_" ) == pOAF->surfaces[i]->name )
  1809.             {
  1810.                 md3Tag_t *pTag = &g_data.tags[f][tagcount];
  1811.                 float tri[3][3];
  1812.                 
  1813.                 strcpy( pTag->name, pOAF->surfaces[i]->name );
  1814.                 
  1815.                 memcpy( tri[0], pTris[0].verts[0], sizeof( float ) * 3 );
  1816.                 memcpy( tri[1], pTris[0].verts[1], sizeof( float ) * 3 );
  1817.                 memcpy( tri[2], pTris[0].verts[2], sizeof( float ) * 3 );
  1818.                 
  1819.                 MD3_ComputeTagFromTri( pTag, tri );
  1820.                 tagcount++;
  1821.             }
  1822.             else
  1823.             {
  1824.                 if ( g_data.surfData[i].verts[f] )
  1825.                     free( g_data.surfData[i].verts[f] );
  1826.                 frameXyz = g_data.surfData[i].verts[f] = calloc( 1, sizeof( float ) * 6 * g_data.surfData[i].header.numVerts );
  1827.                 frameNormals = frameXyz + 3;
  1828.                 
  1829.                 for ( t = 0; t < pOAF->surfaces[i]->numtriangles; t++ )
  1830.                 {
  1831.                     for ( j = 0; j < 3 ; j++ )
  1832.                     {
  1833.                         int index;
  1834.                         
  1835.                         index = g_data.surfData[i].baseTriangles[t].v[j].index;
  1836.                         frameXyz[index*6+0] = pTris[t].verts[j][0];
  1837.                         frameXyz[index*6+1] = pTris[t].verts[j][1];
  1838.                         frameXyz[index*6+2] = pTris[t].verts[j][2];
  1839.                         frameNormals[index*6+0] =  pTris[t].normals[j][0];
  1840.                         frameNormals[index*6+1] =  pTris[t].normals[j][1];
  1841.                         frameNormals[index*6+2] =  pTris[t].normals[j][2];
  1842.                         AddPointToBounds (&frameXyz[index*6], fr->bounds[0], fr->bounds[1] );
  1843.                     }
  1844.                 }
  1845.             }
  1846.         }
  1847.     }
  1848.  
  1849.     if ( strstr( filename, gamedir + 1 ) )
  1850.     {
  1851.         strcpy( g_modelname, strstr( filename, gamedir + 1 ) + strlen( gamedir ) - 1 );
  1852.     }
  1853.     else
  1854.     {
  1855.         strcpy( g_modelname, filename );
  1856.     }
  1857.  
  1858.     FinishModel( type );
  1859.     ClearModel();
  1860. }
  1861.  
  1862. static void ConvertASE( const char *filename, int type, qboolean grabAnims )
  1863. {
  1864.     int i, j;
  1865.     int numSurfaces;
  1866.     int numFrames = -1;
  1867.     SurfaceAnimation_t surfaceAnimations[MAX_ANIM_SURFACES];
  1868.     ObjectAnimationFrame_t objectAnimationFrames[MAX_ANIM_FRAMES];
  1869.     char outfilename[1024];
  1870.  
  1871.     /*
  1872.     ** load ASE into memory
  1873.     */
  1874.     ASE_Load( filename, g_verbose, grabAnims );
  1875.  
  1876.     /*
  1877.     ** process parts
  1878.     */
  1879.     if ( type == TYPE_ITEM )
  1880.     {
  1881.         numSurfaces = GetSurfaceAnimations( surfaceAnimations, "any", -1, -1, -1 );
  1882.  
  1883.         if ( numSurfaces <= 0 )
  1884.             Error( "numSurfaces <= 0" );
  1885.  
  1886.         numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
  1887.  
  1888.         if ( numFrames <= 0 )
  1889.             Error( "numFrames <= 0" );
  1890.  
  1891.         strcpy( outfilename, filename );
  1892.         if ( strrchr( outfilename, '.' ) )
  1893.             *( strrchr( outfilename, '.' ) + 1 ) = 0;
  1894.         strcat( outfilename, "md3" );
  1895.         BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type );
  1896.  
  1897.         // free memory
  1898.         for ( i = 0; i < numSurfaces; i++ )
  1899.         {
  1900.             if ( surfaceAnimations[i].frames )
  1901.             {
  1902.                 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
  1903.                 {
  1904.                     free( surfaceAnimations[i].frames[j].triangles );
  1905.                 }
  1906.                 free( surfaceAnimations[i].frames );
  1907.                 surfaceAnimations[i].frames = 0;
  1908.             }
  1909.         }
  1910.     }
  1911.     else if ( type == TYPE_PLAYER )
  1912.     {
  1913.         qboolean tagTorso = qfalse;
  1914.         qboolean tagHead = qfalse;
  1915.         qboolean tagWeapon = qfalse;
  1916.  
  1917.         //
  1918.         // verify that all necessary tags exist
  1919.         //
  1920.         numSurfaces = ASE_GetNumSurfaces();
  1921.         for ( i = 0; i < numSurfaces; i++ )
  1922.         {
  1923.             const char    *surfaceName;
  1924.  
  1925.             surfaceName = ASE_GetSurfaceName( i );
  1926.             if ( !surfaceName ) {
  1927.                 continue;
  1928.             }
  1929.             if ( !strcmp( surfaceName, "tag_head" ) )
  1930.             {
  1931.                 tagHead = qtrue;
  1932.             }
  1933.             if ( !strcmp( surfaceName, "tag_torso" ) )
  1934.             {
  1935.                 tagTorso = qtrue;
  1936.             }
  1937.             if ( !strcmp( surfaceName, "tag_weapon" ) )
  1938.             {
  1939.                 tagWeapon = qtrue;
  1940.             }
  1941.         }
  1942.  
  1943.         if ( !tagWeapon )
  1944.         {
  1945.             Error( "Missing tag_weapon!" );
  1946.         }
  1947.         if ( !tagTorso )
  1948.         {
  1949.             Error( "Missing tag_torso!" );
  1950.         }
  1951.         if ( !tagWeapon )
  1952.         {
  1953.             Error( "Missing tag_weapon!" );
  1954.         }
  1955.  
  1956.         // get all upper body surfaces
  1957.         numSurfaces = GetSurfaceAnimations( surfaceAnimations, "u_", -1, -1, g_data.maxUpperFrames );
  1958.         numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
  1959.         strcpy( outfilename, filename );
  1960.         if ( strrchr( outfilename, '/' ) )
  1961.             *( strrchr( outfilename, '/' ) + 1 ) = 0;
  1962.  
  1963.         if ( g_data.currentLod == 0 )
  1964.         {
  1965.             strcat( outfilename, "upper.md3" );
  1966.         }
  1967.         else
  1968.         {
  1969.             char temp[128];
  1970.  
  1971.             sprintf( temp, "upper_%d.md3", g_data.currentLod );
  1972.             strcat( outfilename, temp );
  1973.         }
  1974.         
  1975.         BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type );
  1976.  
  1977.         // free memory
  1978.         for ( i = 0; i < numSurfaces; i++ )
  1979.         {
  1980.             if ( surfaceAnimations[i].frames )
  1981.             {
  1982.                 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
  1983.                 {
  1984.                     free( surfaceAnimations[i].frames[j].triangles );
  1985.                 }
  1986.                 free( surfaceAnimations[i].frames );
  1987.                 surfaceAnimations[i].frames = 0;
  1988.             }
  1989.         }
  1990.  
  1991.         // get lower body surfaces
  1992.         numSurfaces = GetSurfaceAnimations( surfaceAnimations, "l_", g_data.lowerSkipFrameStart, g_data.lowerSkipFrameEnd, -1 );
  1993.         numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
  1994.         strcpy( outfilename, filename );
  1995.         if ( strrchr( outfilename, '/' ) )
  1996.             *( strrchr( outfilename, '/' ) + 1 ) = 0;
  1997.  
  1998.         if ( g_data.currentLod == 0 )
  1999.         {
  2000.             strcat( outfilename, "lower.md3" );
  2001.         }
  2002.         else
  2003.         {
  2004.             char temp[128];
  2005.  
  2006.             sprintf( temp, "lower_%d.md3", g_data.currentLod );
  2007.             strcat( outfilename, temp );
  2008.         }
  2009.         BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type );
  2010.  
  2011.         // free memory
  2012.         for ( i = 0; i < numSurfaces; i++ )
  2013.         {
  2014.             if ( surfaceAnimations[i].frames )
  2015.             {
  2016.                 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
  2017.                 {
  2018.                     free( surfaceAnimations[i].frames[j].triangles );
  2019.                 }
  2020.                 free( surfaceAnimations[i].frames );
  2021.                 surfaceAnimations[i].frames = 0;
  2022.             }
  2023.         }
  2024.  
  2025.         // get head surfaces
  2026.         numSurfaces = GetSurfaceAnimations( surfaceAnimations, "h_", -1, -1, g_data.maxHeadFrames );
  2027.         numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
  2028.         strcpy( outfilename, filename );
  2029.         if ( strrchr( outfilename, '/' ) )
  2030.             *( strrchr( outfilename, '/' ) + 1 ) = 0;
  2031.  
  2032.         if ( g_data.currentLod == 0 )
  2033.         {
  2034.             strcat( outfilename, "head.md3" );
  2035.         }
  2036.         else
  2037.         {
  2038.             char temp[128];
  2039.  
  2040.             sprintf( temp, "head_%d.md3", g_data.currentLod );
  2041.             strcat( outfilename, temp );
  2042.         }
  2043.         BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type );
  2044.  
  2045.         // free memory
  2046.         for ( i = 0; i < numSurfaces; i++ )
  2047.         {
  2048.             if ( surfaceAnimations[i].frames )
  2049.             {
  2050.                 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
  2051.                 {
  2052.                     free( surfaceAnimations[i].frames[j].triangles );
  2053.                 }
  2054.                 free( surfaceAnimations[i].frames );
  2055.                 surfaceAnimations[i].frames = 0;
  2056.             }
  2057.         }
  2058.     }
  2059.     else if ( type == TYPE_WEAPON )
  2060.     {
  2061.         // get the weapon surfaces
  2062.         numSurfaces = GetSurfaceAnimations( surfaceAnimations, "w_", -1, -1, -1 );
  2063.         numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
  2064.  
  2065.         strcpy( outfilename, filename );
  2066.         if ( strrchr( outfilename, '.' ) )
  2067.             *( strrchr( outfilename, '.' ) + 1 ) = 0;
  2068.         strcat( outfilename, "md3" );
  2069.         BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, type );
  2070.  
  2071.         // free memory
  2072.         for ( i = 0; i < numSurfaces; i++ )
  2073.         {
  2074.             if ( surfaceAnimations[i].frames )
  2075.             {
  2076.                 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
  2077.                 {
  2078.                     free( surfaceAnimations[i].frames[j].triangles );
  2079.                 }
  2080.                 free( surfaceAnimations[i].frames );
  2081.                 surfaceAnimations[i].frames = 0;
  2082.             }
  2083.         }
  2084.  
  2085.         // get the flash surfaces
  2086.         numSurfaces = GetSurfaceAnimations( surfaceAnimations, "f_", -1, -1, -1 );
  2087.         numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
  2088.  
  2089.         strcpy( outfilename, filename );
  2090.         if ( strrchr( outfilename, '.' ) )
  2091.             *strrchr( outfilename, '.' ) = 0;
  2092.         strcat( outfilename, "_flash.md3" );
  2093.         BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, TYPE_ITEM );
  2094.  
  2095.         // get the barrel surfaces
  2096.         numSurfaces = ASE_GetNumSurfaces();
  2097.         for( i = 0; i < numSurfaces; i++ ) {
  2098.             const char *surfaceName = ASE_GetSurfaceName( i );
  2099.             if( surfaceName[0] == 'b' && surfaceName[1] == '_' ) {
  2100.                 break;
  2101.             }
  2102.         }
  2103.         if( i == numSurfaces ) {
  2104.             i = -1;
  2105.         }
  2106.         numSurfaces = GetSurfaceAnimations( surfaceAnimations, "b_", -1, -1, -1 );
  2107.         if ( i != -1 && numSurfaces ) {
  2108.             numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
  2109.  
  2110.             strcpy( outfilename, filename );
  2111.             if ( strrchr( outfilename, '.' ) )
  2112.                 *strrchr( outfilename, '.' ) = 0;
  2113.  
  2114.             if ( g_data.currentLod == 0 )
  2115.             {
  2116.                 strcat( outfilename, "_barrel.md3" );
  2117.             }
  2118.             else
  2119.             {
  2120.                 char temp[128];
  2121.  
  2122.                 sprintf( temp, "_barrel_%d.md3", g_data.currentLod );
  2123.                 strcat( outfilename, temp );
  2124.             }
  2125.  
  2126.             BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, TYPE_ITEM );
  2127.         }
  2128.  
  2129.         // free memory
  2130.         for ( i = 0; i < numSurfaces; i++ )
  2131.         {
  2132.             if ( surfaceAnimations[i].frames )
  2133.             {
  2134.                 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
  2135.                 {
  2136.                     free( surfaceAnimations[i].frames[j].triangles );
  2137.                 }
  2138.                 free( surfaceAnimations[i].frames );
  2139.                 surfaceAnimations[i].frames = 0;
  2140.             }
  2141.         }
  2142.     }
  2143.     else if ( type == TYPE_HAND )
  2144.     {
  2145.         // get the hand tags
  2146.         numSurfaces = GetSurfaceAnimations( surfaceAnimations, "tag_", -1, -1, -1 );
  2147.         numFrames = SurfaceOrderToFrameOrder( surfaceAnimations, objectAnimationFrames, numSurfaces );
  2148.  
  2149.         strcpy( outfilename, filename );
  2150.         if ( strrchr( outfilename, '.' ) )
  2151.             *strrchr( outfilename, '.' ) = 0;
  2152.         strcat( outfilename, "_hand.md3" );
  2153.         BuildAnimationFromOAFs( outfilename, objectAnimationFrames, numFrames, TYPE_HAND );
  2154.  
  2155.         // free memory
  2156.         for ( i = 0; i < numSurfaces; i++ )
  2157.         {
  2158.             if ( surfaceAnimations[i].frames )
  2159.             {
  2160.                 for ( j = 0; j < surfaceAnimations[i].numFrames; j++ )
  2161.                 {
  2162.                     free( surfaceAnimations[i].frames[j].triangles );
  2163.                 }
  2164.                 free( surfaceAnimations[i].frames );
  2165.                 surfaceAnimations[i].frames = 0;
  2166.             }
  2167.         }
  2168.     }
  2169.     else
  2170.     {
  2171.         Error( "Unknown type passed to ConvertASE()" );
  2172.     }
  2173.  
  2174.     g_data.currentLod = 0;
  2175.     g_data.lodBias = 0;
  2176.     g_data.maxHeadFrames = 0;
  2177.     g_data.maxUpperFrames = 0;
  2178.     g_data.lowerSkipFrameStart = 0;
  2179.     g_data.lowerSkipFrameEnd = 0;
  2180.     VectorCopy( vec3_origin, g_data.aseAdjust );
  2181.  
  2182.     // unload ASE from memory
  2183.     ASE_Free();
  2184. }
  2185.